'''
Created on 21.9.2011

@author: mphkh
'''
from datetime import date
from datetime import datetime
from datetime import timedelta
from TimeUtils.daterolling import *
from TimeUtils.daycount import *
from TimeUtils.utils import *

class CashFlow(object):
    '''
    CashFlow implements a cash-flow entity that consists of date, daysPeriod, interests and amount 
    CashFlow(cfdate, notional, daysPeriod=0, interests=0, amount=0, amortization=0)
    Parameters: 
        cfdate:        date of cashflow
        daysPeriod:    days since last cashflow (or beginning) to date
        yearfrac:      year fraction of cashflow (street method)
        interests:     interests rate
        amount:        cashflow payable on cfdate
        amortization:  amortization amount on notional
        notional:      remaining notional (after amortization on date) 
    Returns:
    '''
    def __init__(self, cfdate, notional, daysPeriod=0, yearfrac=0, interests=0, amount=0, amortization=0):
        self.cfdate         = cfdate
        self.notional       = notional
        self.daysPeriod     = daysPeriod
        self.yearfrac       = yearfrac
        self.interests      = interests
        self.amount         = amount
        self.amortization   = amortization

class CashFlowSchedule(object):
    '''
    CashFlowSchedule generates series of cash-flows. Backward generation of cash-flows is assumed (starting at maturity)
    CashFlows generated are accessible by calling cashflows() on this object which returns ordered list of cashflows in
    increasing order by date.
    Parameters: 
        firstinterestdate:     Starting date(or issue date if applicable) of cash-flows
        maturitydate:          Last cash-flow payable
        daterollingconvention: DateRollingConvention object (actual/following/modifiedfollowing/preceding/modifiedpreceding)
        frequencyyear:         Number of cash-flows on annual basis
    '''
    def __init__(self, caldar, issuedate, firstinterestdate, firstcoupondate, maturitydate, daterollingconvention, daycountbasis, frequencyyear=1):
        self.caldar                 = caldar
        self.issuedate              = issuedate
        self.firstinterestdate      = firstinterestdate
        self.firstcoupondate        = firstcoupondate
        self.maturitydate           = maturitydate
        self.daterollingconvention  = daterollingconvention
        self.frequencyyear          = frequencyyear


    def cashflows(self):
        '''
        Cashflows returns schedule of cash-flows as a list of CashFlow objects
        Parameters: 
        Returns:
            list of CashFlow objects
        pass
        '''
        cf= []
        n = self.maturitydate.year - self.firstcoupondate.year
        cashflowdate = self.firstcoupondate
        daysPeriod = float(self.firstcoupondate.toordinal() - self.firstinterestdate.toordinal())
        yearfrac = 0

        'Add first coupondate date to our cashflow sequence'
        cf.append(CashFlow(self.firstcoupondate, 0.0, daysPeriod, yearfrac, 0.0, 0.0))
        i = 1
        while cashflowdate<self.maturitydate:
            'We need to cast exception if cashflow day doesnt exist for given month.'
            cashflowdate = addmonth(self.firstcoupondate, i*12/self.frequencyyear)
            if self.daterollingconvention == DateRollingConvention.following:
                cashflowdate = following(self.caldar, cashflowdate)
            elif self.daterollingconvention == DateRollingConvention.modifiedfollowing:
                cashflowdate = modifiedfollowing(self.caldar, cashflowdate)
            elif self.daterollingconvention == DateRollingConvention.preceding:
                cashflowdate = preceding(self.caldar, cashflowdate)
            elif self.daterollingconvention == DateRollingConvention.modifiedpreceding:
                cashflowdate = modifiedpreceding(self.caldar, cashflowdate)
            else:
                pass
            daysPeriod = float(cashflowdate.toordinal() - cf[i-1].cfdate.toordinal())
            yearfrac = i/self.frequencyyear
            cashFlow = CashFlow(cashflowdate, 0.0, daysPeriod, yearfrac, 0.0, 0.0)
            cf.append(cashFlow)
            i = i+1
        return cf
